/*
 *  tf.h
 *  perceel
 *
 *  Created by Nicola Gigante on 13/03/08.
 *  Copyright 2008 Nicola Gigante. All rights reserved.
 *
 */

#ifndef __TF_H__
#define __TF_H__

#include <algorithm>

#include <QMetaType>
#include <QSize>
#include <QtDebug>

class TF;

#include "polynomial.h"

/*!
	\brief Classe the rappresenta una funzione di trasferimento, come rapporto
 tra due polinomi di variabile s.
 
 Un oggetto di classe TF rappresenta una funzione di trasferimento nel dominio di
 Laplace, rappresentata in forma di Bode, ovvero con i poli e gli zeri in evidenza.
 La fdt infatti si costruisce aggiungendo o impostando i numeri complessi che formano
 poli e zeri, tramite le funzioni addRoot(Complex), addPole(Complex), setRoot(Complex)
 e setPole(Complex). 
 I poli e gli zeri della funzione sono disponibili tramite le funzioni roots() e poles().
 Le funzioni removeRoot(int) e removePole(int) permettono di rimuovere poli e zeri.
 
 E' possibile costruire la fdt anche impostando direttamente i polinomi numeratore
 e denominatore tramite la funzione setNumerator(Polynomial) e setDenominator(Polynomial).
 
 Le due principali operazioni permesse dalla classe TF sono:
	- La funzione eval(Complex) calcola il valore assunto dalla funzione per un determinato valore di s.
	- La funzione closedLoop(Real, ReactionType) restituisce la corrispondente funzione di trasferimento a catena chiusa
 
 Varie funzioni forniscono informazioni sulla funzione di trasferimento:
	- Le funzioni numerator() denominator() roots() e poles() forniscono accesso a tutti gli elementi
	  della fdt.
	- La funzione isFract() indica se si tratta di una funzione fratta, ovvero se ci sono poli.
 
 \note La classe è registrata nel meta-object system di Qt tramite la macro Q_DECLARE_METATYPE
 
 \see TFRenderer La classe che rappresenta graficamente la funzione.
 \see PlotWidget Classe base per i diagrammi ricavati dalle funzioni di trasferimento.
 */
class TF {

	Polynomial m_num; //!< Variabile interna per il polinomio numeratore
	Polynomial m_den; //!< Variabile interna per il polinomio denominatore
	
	QList<Complex> m_roots; //!< Lista degli zeri
	QList<Complex> m_poles; //!< Lista dei poli
	
public:
	enum ReactionType
	{
		Negative = 0,
		Positive = 1
	};

	enum ViewMode
	{
		Polynomials,
		Poles
	};
	
	enum RootType
	{
		Root,
		Pole
	};
	
	TF(const TF &tf); //!< Costruttore di copie, crea una TF identica alla precedente.
	TF(Polynomial num = 1, Polynomial den = 1, ViewMode vm = Polynomials); //!< Costruttore di default.
	
	// Accesso ai membri
	Polynomial numerator() const { return m_num; } //!< Restituisce il polinomio numeratore
	Polynomial denominator() const { return m_den; } //!< Restituisce il polinomio denominatore
	
	QList<Complex> roots() const { return m_roots; } //!< Restituisce la lista degli zeri
	QList<Complex> poles() const { return m_poles; } //!< Restituisce la lista dei poli
	
	//! Indica se la funzione è fratta, ovvero restituisce true se esistono poli.
	bool isFract() const { return m_den.grade() != 0 || m_den.term(0) != Complex(1); }
	
	ViewMode viewMode() const { return m_viewMode; } //!< Modalità di rappresentazione. Non usato
	void setViewMode(ViewMode viewMode) { m_viewMode = viewMode; } //!< Modalità di rappresentazione. Non usato
	
	void addRoot(Complex root); //!< Aggiunge uno zero
	void addPole(Complex pole); //!< Aggiunge un polo

	void setRoot(int i, Complex root, int order = 0); //!< Imposta il valore e l'ordine di uno zero
	void setPole(int i, Complex pole, int order = 0); //!< Imposta il valore e l'ordine di un polo
	
	void removeRoot(int i); //!< Rimuove uno zero
	void removePole(int i); //!< Rimuove un polo
	
	void setNumerator(Polynomial num); //!< Imposta il polinomio numeratore
	void setDenominator(Polynomial den); //!< Imposta il polinomio denominatore
	
	Complex eval(Complex s); //!< Valuta la funzione di trasferimento in funzione di s
	
	TF closedLoop(Real reaction, ReactionType rtype = Negative); //!< Ricava la funzione di trasferimento a catena chiusa
	
private:
	ViewMode m_viewMode; //!< Modalità di visualizzazione. Non usato.
	
	void updateNumerator(); //!< Funzione che sincronizza il polinomio numeratore con la lista degli zeri
	void updateDenominator(); //!< Funzione che sincronizza il polinomio denominatore con la lista dei poli
};

Q_DECLARE_METATYPE(TF)

#endif
